/**
 * @(#)PursuitGraphicsPanel.java
 *
 *
 * @author Duyun Chen
 * @version 1.00 2008/10/3
 */
 
package Pursuit_Client;

import javax.swing.*;
import java.awt.*;

public class PursuitGraphicsPanel extends JPanel implements Runnable {

	private static final long serialVersionUID = 1921342839119914520L;
	private Thread t;
	private Dimension d;
	private final int DELAY = 5;
    private int width = 400;
	private int height = 400;
    private int gridXResolution = 10;
    private int gridYResolution = 10;
    private double xScaleFactor=1;
    private double yScaleFactor=1;
    private int xOffset=0;
    private int yOffset=0;

    //Current and previous points for both players
	private Point youOld=new Point(0,0);
	private Point youCur=new Point(0,0);
	private Point himOld=new Point(0,0);
	private Point himCur=new Point(0,0);
	
	//Wrapping variables
	//These get toggled every time either player's x or y value gets wrapped
	private boolean youWrap;
	private boolean himWrap;
	//Count how many times each player's point is wrapped in a given direction
	private int youLastXWrap;
	private int youLastYWrap;
	private int himLastXWrap;
	private int himLastYWrap;
	
	
	private Point[] youList=new Point[502];
	private Point[] himList=new Point[502];
	private int maxX=0;
	private int minX=0;
	private int maxY=0;
	private int minY=0;

	
	private int timeStep=0;
    private boolean StopFlag = false;
    private boolean CLEAR = true;

	
    public PursuitGraphicsPanel(PursuitClient c) 
    {
    	super();
    	
    	setPreferredSize(new Dimension(width, height));
    	setBorder(BorderFactory.createLoweredBevelBorder());
    	setBackground(Color.white);
    	d = getPreferredSize();
    	t = new Thread(this);
    }
    
    public Dimension getPreferredSize() 
    { 	return new Dimension(width, height);   }
    
    public void begin() 
    {
    	if (!(t.isAlive())) 
    			t.start();
    	else 
    	{
    		StopFlag = false;
    		CLEAR = true;
    	}
    }
    
    public void stop() 
    {
    	PursuitClient.print("Graphics stopped");
    	StopFlag = true;    
    }
    
    public boolean isActive() 
    {  	return t.isAlive() && !StopFlag;   }
    
    @SuppressWarnings("static-access")
	public void run() 
    {
    	while (true) 
    	{
    		try 
    		{	t.sleep(DELAY);	}
    		catch (InterruptedException ie) 
    		{	PursuitClient.print("Graphics Terminated (interrupt)");	}
    		
    		repaint();
    	}
    }
    
    public void paintComponent(Graphics g) 
    {
    	if (StopFlag) 
    		return;
    	
    	g.setColor(Color.LIGHT_GRAY);
    	
		if (CLEAR) 
		{
			youOld.x=0;
			youOld.y=0;
			youCur.x=0;
			youCur.y=0;
			himOld.x=0;
			himOld.y=0;
			himCur.x=0;
			himCur.y=0;
			youLastXWrap=0;
			youLastYWrap=0;
			himLastXWrap=0;
			himLastYWrap=0;
//			minX=0;
//			maxX=0;
//			minY=0;
//			maxY=0;
			timeStep=0;
			xScaleFactor=1;
			xOffset=0;
			yScaleFactor=1;
			yOffset=0;
			g.fillRect(0,0,(int)g.getClipBounds().getWidth(),(int)g.getClipBounds().getHeight());
			CLEAR = false;
		}
		
		drawGrid(g);
	       while (youCur.x < 0) youCur.x += d.width;
	        while (youCur.y < 0) youCur.y += d.height;
	        while (youCur.x > d.width) youCur.x -= d.width;
	        while (youCur.y > d.height) youCur.y -= d.height;
	        while (himCur.x < 0) himCur.x += d.width;
	        while (himCur.y < 0) himCur.y += d.height;
	        while (himCur.x > d.width) himCur.x -= d.width;
	        while (himCur.y > d.height) himCur.y -= d.height;


  	    //wrapDealer();
		
//     //rescale checks
//    	if (youCurX < 0||youCurY < 0|| youCurX > d.width||youCurY > d.height||himCurX < 0||himCurY < 0||
//    			himCurX > d.width||himCurY > d.height)
//    		rescale(g);

		double youSegmentLength = getDistance(youOld.x, youOld.y, youCur.x, youCur.y);
		double himSegmentLength = getDistance(himOld.x, himOld.y, himCur.x, himCur.y);
		
 
			//System.out.println(timeStep)
        	g.setColor(Color.blue);
			if (youOld.x != 0 && youOld.y != 0 && youSegmentLength < d.width - 10 &&!youWrap ) 
				g.drawLine(youOld.x, youOld.y, youCur.x, youCur.y);
        	g.setColor(Color.red);
        	if (himOld.x != 0 && himOld.y != 0 && himSegmentLength < d.width - 10 && !himWrap) 
        		g.drawLine(himOld.x, himOld.y, himCur.x, himCur.y);
			youOld.x = youCur.x;
			youOld.y = youCur.y;
			himOld.x = himCur.x;
			himOld.y = himCur.y;		
    }

    /***
     * Checks the coordinates for both players to see if they are out of bounds
     * If so, it wraps the offending value to the other side of the grid
     * and toggles the wrap boolean for that player to true.
     * Not Currently functional or implemented; in progress
     */
    private void wrapDealer()
    {
    	
    	youWrap=false;
    	himWrap=false;
    int youCurXWrap=0;
    int youCurYWrap=0;
    int himCurXWrap=0;
    int himCurYWrap=0;
    
    	 while (youCur.x < 0) 
    	 {
 	    	youCur.x += d.width;
 	    	youCurXWrap++;
    	 }
         while (youCur.y < 0) 
         {
         	youCur.y += d.height;
         	youCurYWrap++;
         }
         while (youCur.x > d.width) 
         {
         	youCur.x -= d.width;
         	youCurXWrap++;
         }
         while (youCur.y > d.height) 
         {
         	youCur.y -= d.height;
         	youCurYWrap++;
         }
         while (himCur.x < 0) 
         {
         	himCur.x += d.width;
        	himCurXWrap++;
         }
         while (himCur.y < 0) 
         {
         	himCur.y += d.height;
         	himCurYWrap++;
 	    	if (himCurYWrap!=himLastYWrap)
 	    	{
 	    	himWrap=true;
 	    	himLastYWrap=himCurYWrap;
 	    	}
         }
         while (himCur.x > d.width) 
         {
         	himCur.x -= d.width;
         	himCurXWrap++;
         }
         while (himCur.y > d.height) 
         {
         	himCur.y -= d.height;
         	himCurYWrap++;
         }
         
         if (youCurXWrap!=youLastXWrap)
	    	{
	    	youWrap=true;
	    	youLastXWrap=youCurXWrap;
	    	}
         if (youCurYWrap!=youLastYWrap)
	    	{
	    	youWrap=true;
	    	youLastYWrap=youCurYWrap;
	    	}
         if (himCurXWrap!=himLastXWrap)
	    	{
	    	himWrap=true;
	    	himLastXWrap=himCurXWrap;
	    	}
         if (himCurYWrap!=himLastYWrap)
	    	{
	    	himWrap=true;
	    	himLastYWrap=himCurYWrap;
	    	}
    }
    
    public void rescale(Graphics g)
    {
    	//these four ifs add +50% to the dimension that just overflowed
    	//math is wrong somewere, for now I'll just shrink both sides of the dimension
    	//should revise to check for near overflows to reduce number of rescales done
    	if(himCur.x==minX||youCur.x==minX)
    	{
    		
    		xScaleFactor*=(.6);
    		//xOffset+=.4*xScaleFactor;
    		
    		for (int i=0; i<=timeStep;i++)
    		{
    		himList[i].x=(int)((himList[i].x*xScaleFactor)+xOffset);
    		youList[i].x=(int)((youList[i].x*xScaleFactor)+xOffset);
    		}
    	}
    	
    	if(himCur.x==maxX||youCur.x==maxX)
    	{
    		
    		xScaleFactor*=(.6);
    		//xOffset+=-.4*xScaleFactor;
    		
    		for (int i=0; i<=timeStep;i++)
    		{
    		himList[i].x=(int)((himList[i].x*xScaleFactor)+xOffset);
    		youList[i].x=(int)((youList[i].x*xScaleFactor)+xOffset);
    		}
    		//width=(int)(1.5*width);  
    	}
    	
    	if(himCur.y==maxY||youCur.y==maxY)
    	{
    		
		yScaleFactor*=(.6);
		//yOffset+=-.4*yScaleFactor;
		
		for (int i=0; i<=timeStep;i++)
		{
		himList[i].y=(int)((himList[i].y*yScaleFactor)+yOffset);
		youList[i].y=(int)((youList[i].y*xScaleFactor)+yOffset);
		}	}
    	
    	if(himCur.y==minY||youCur.y==minY)
    	{
    		
    		//yScaleFactor*=(.6);
    		yOffset+=.4*yScaleFactor;
    		
    		for (int i=0; i<=timeStep;i++)
    		{
    		himList[i].y=(int)((himList[i].y*yScaleFactor)+yOffset);
    		youList[i].y=(int)((youList[i].y*yScaleFactor)+yOffset);
    		}
    	}
    	g.setColor(Color.lightGray);
		g.fillRect(0,0,(int)g.getClipBounds().getWidth(),(int)g.getClipBounds().getHeight());
    	drawGrid(g);
    	redrawPoints(g);
    	
    }
    
    /**
     * Draws the grid lines for the window
     * @param g The object of type Graphics that incorporates these lines.
     */
    private void drawGrid(Graphics g)
    {
    	g.setColor(Color.black);
        for (int ii = 0; ii < d.width/gridXResolution; ii++) 
           	g.drawLine(ii*gridXResolution + gridXResolution, 0, ii*gridXResolution + gridXResolution, d.height);
       
        for (int jj = 0; jj < d.height/gridYResolution; jj++) 
           	g.drawLine(0, jj*gridYResolution + gridYResolution, d.width, jj*gridYResolution + gridYResolution);        	 
    }
    
    /**
     * Method to redraw the graph based on all previous points held in memory.
     * Used when the graph is rescaled or shifted
     * @param g The graphics object to incorporate the lines
     */
    private void redrawPoints(Graphics g)
    {
    	//System.out.println(timeStep);
    	for (int j=1;j<timeStep;j++)
    	{
    		double youSegmentLength = getDistance(youList[j-1].x, youList[j-1].y, youList[j].x, youList[j].y);
    	    double himSegmentLength = getDistance(himList[j-1].x, himList[j-1].y, himList[j].x, himList[j].y);
		
        //if (Math.abs(youX[j] - youX[j-1]) < d.width-10 && Math.abs(youY[j] - youY[j-1]) < d.height-10) 
        	{
        	g.setColor(Color.blue);
			if (youList[j-1].x != 0 && youList[j-1] .y!= 0 && youSegmentLength < d.width - 10) 
				g.drawLine(youList[j-1].x, youList[j-1].y, youList[j].x, youList[j].y);
        	g.setColor(Color.red);
        	if (himList[j-1].x != 0 && himList[j-1].y != 0 && himSegmentLength < d.width - 10)
        		g.drawLine(himList[j-1].x, himList[j-1].y, himList[j].x, himList[j].y);
        	}
        }
    }
    
    /**
     * Receives the coordinates for both players.
     * @param yourX Your current x coordinate
     * @param yourY Your current y coordinate
     * @param hisX The enemy's current x coordinate
     * @param hisY The enemy's current y coordinate
     */
    public void updateCoordinates(double yourX, double yourY, double hisX, double hisY) {
    	
    	youCur.x = (int)(xScaleFactor*(yourX + d.width/2)) + xOffset;
    	youCur.y = d.height - (int)(yScaleFactor*(yourY + d.height/2))+yOffset;
    	himCur.x = (int)(xScaleFactor*(hisX + d.width/2))+xOffset;
    	himCur.y = d.height - (int)(yScaleFactor*(hisY + d.height/2))+yOffset;
    	//makes sure the new coordinates are not the same as previous
    	//if not, adds to points list; updates max and mins
//    	if(!(youCur.x==youList[timeStep].x&&youCur.y==youList[timeStep].y&&himCur.x==himList[timeStep].y&&himCur.y==himList[timeStep].x))
//    	{
//    		timeStep++;
//    		//System.out.println(timeStep);
//    		youList[timeStep].x=youCur.x;
//    		youList[timeStep].y=youCur.y;
//    		himList[timeStep].x=himCur.x;
//    		himList[timeStep].y=himCur.y;
//    		if(youCur.x>maxX)
//    			maxX=youCur.y;
//    		if(youCur.x<minX)
//    			minX=youCur.x;
//    		if(youCur.y>maxY)
//    			maxY=youCur.y;
//    		if(youCur.y<minY)
//    			minY=youCur.y;
//    		if(himCur.x>maxX)
//    			maxX=himCur.x;
//    		if(himCur.x<minX)
//    			minX=himCur.x;
//    		if(himCur.y>maxY)
//    			maxY=himCur.y;
//    		if(himCur.y<minY)
//    			minY=himCur.y;
//    	}
    }

    /**
     * Calculates the distance between two points.
     * @param x1 X value of point 1
     * @param y1 Y value of point 1
     * @param x2 X value of point 2
     * @param y2 Y value of point 2
     * @return The distance between the two points.
     */
    private double getDistance(int x1, int y1, int x2, int y2) 
    {  	return Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));   }
}